unit uGlsFrame;
(*
  Description: Implementation of a frame class defining a local coordinate
  system. The frame class contains functionality to convert
  local coordinate systems to and from global (so called canonical)
  coordinates.
  Started by Ton van den Heuvel, 15-08-2002
*)

interface

uses
  uGlsVector,
  uGlsONB,
  uTransformationList,
  uGlsMatrix;

type
  TCoordinateFrame = class
  private
    FOrigin: TPoint3d;
    FONB: TONB;
    FLCTransformationList: TTransformationList;
    FCLTransformationList: TTransformationList;
  public
    property Origin: TPoint3d read FOrigin write FOrigin;
    property ONB: TONB read FONB write FONB;
    property LCTransformationList: TTransformationList
      read FLCTransformationList write FLCTransformationList;
    property CLTransformationList: TTransformationList
      read FCLTransformationList write FCLTransformationList;

    constructor Create; overload;
    constructor Create(AOrigin: TPoint3d; AONB: TONB); overload;
    destructor Destroy; override;

    procedure SetTransformationLists;

    function Local2Canonical(u, v, w: real): TPoint3d; overload;
    function Local2Canonical(APoint3d: TPoint3d): TPoint3d; overload;
    function Local2Canonical(AVector3d: TVector3d): TVector3d; overload;
    function Canonical2Local(x, y, z: real): TPoint3d; overload;
    function Canonical2Local(APoint3d: TPoint3d): TPoint3d; overload;
    function Canonical2Local(AVector3d: TVector3d): TVector3d; overload;

    function Rotate(const Angle: real; const APoint3d: TPoint3d;
      const Axis: TAxis): TPoint3d; overload;
    { Pre: APoint3d <> nil & Angle is in radians
      Ret: A point rotated around the local axis 'Axis' with the specified
      angle. }
    function Rotate(const Angle: real; const AVector3d: TVector3d;
      const Axis: TAxis): TVector3d; overload;
    { Pre: AVector3d <> nil & Angle is in radians
      Ret: A vector rotated around the local axis 'Axis' with the specified
      angle. }

    procedure Assign(AFrame: TCoordinateFrame);
  end;

implementation

{ TFrame }

constructor TCoordinateFrame.Create;
{ Pre: True
  Post: A standard frame has been created with origin (0, 0, 0) and the
  standard x, y, z vectors (y pointing upwards and z in the screen). }
begin
  inherited Create;
  FOrigin := TPoint3d.Create(0, 0, 0);
  FONB := TONB.CreateStandard;

  SetTransformationLists;
end;

constructor TCoordinateFrame.Create(AOrigin: TPoint3d; AONB: TONB);
begin
  inherited Create;
  FOrigin := TPoint3d.Create;
  FOrigin.Assign(AOrigin);
  FONB := TONB.Create;
  FONB.Assign(AONB);

  SetTransformationLists;
end;

procedure TCoordinateFrame.SetTransformationLists;
var
  OriginMatrix: TGLMatrix;
  ONBMatrix: TGLMatrix;
begin
  { Create transformationlists }
  FLCTransformationList := TTransformationList.Create;
  FCLTransformationList := TTransformationList.Create;

  { Add canonical to local coordinates transformation matrices to the
    transformation list }
  OriginMatrix := TGLMatrix.Create;
  OriginMatrix.SetTranslateMatrix(-FOrigin.x, -FOrigin.y, -FOrigin.z);
  ONBMatrix := TGLMatrix.Create;
  ONBMatrix.Assign(FONB.CLTransformMatrix);
  FCLTransformationList.AddMatrix(OriginMatrix);
  FCLTransformationList.AddMatrix(ONBMatrix);

  { Add local to canonical coordinates transformation matrices to the
    transformation list }
  OriginMatrix := TGLMatrix.Create;
  OriginMatrix.SetTranslateMatrix(FOrigin.x, FOrigin.y, FOrigin.z);
  ONBMatrix.Create;
  ONBMatrix.Assign(FONB.LCTransformMatrix);
  FLCTransformationList.AddMatrix(ONBMatrix); // Notice the different
  FLCTransformationList.AddMatrix(OriginMatrix); // order!
end;

destructor TCoordinateFrame.Destroy;
begin
  FOrigin.Destroy;
  FONB.Destroy;
  FLCTransformationList.Destroy;
  FCLTransformationList.Destroy;
  inherited Destroy;
end;

function TCoordinateFrame.Canonical2Local(x, y, z: real): TPoint3d;
var
  APoint3d: TPoint3d;
begin
  APoint3d := TPoint3d.Create(x, y, z);
  Result := FCLTransformationList.Transform(APoint3d);
  APoint3d.Destroy;
end;

function TCoordinateFrame.Canonical2Local(APoint3d: TPoint3d): TPoint3d;
begin
  Result := FCLTransformationList.Transform(APoint3d);
end;

function TCoordinateFrame.Canonical2Local(AVector3d: TVector3d): TVector3d;
begin
  Result := FCLTransformationList.Transform(AVector3d);
end;

function TCoordinateFrame.Local2Canonical(u, v, w: real): TPoint3d;
var
  APoint3d: TPoint3d;
begin
  APoint3d := TPoint3d.Create(u, v, w);
  Result := FLCTransformationList.Transform(APoint3d);
  APoint3d.Destroy;
end;

function TCoordinateFrame.Local2Canonical(APoint3d: TPoint3d): TPoint3d;
begin
  Result := FLCTransformationList.Transform(APoint3d);
end;

function TCoordinateFrame.Local2Canonical(AVector3d: TVector3d): TVector3d;
begin
  Result := FLCTransformationList.Transform(AVector3d);
end;

function TCoordinateFrame.Rotate(const Angle: real; const APoint3d: TPoint3d;
  const Axis: TAxis): TPoint3d;
{ Pre: APoint3d <> nil & Angle is in radians
  Ret: A point rotated around the local axis 'Axis' with the specified
  angle. }
var
  RotationMatrix: TGLMatrix;
  GlobalPoint: TPoint3d;
  RotatedPoint: TPoint3d;
begin
  RotationMatrix := TGLMatrix.Create;
  RotationMatrix.SetRotationMatrix(Angle, Axis);
  GlobalPoint := Local2Canonical(APoint3d);
  RotatedPoint := RotationMatrix.Multiply(GlobalPoint);
  Result := Canonical2Local(RotatedPoint);
  RotationMatrix.Destroy;
  GlobalPoint.Destroy;
  RotatedPoint.Destroy;
end;

function TCoordinateFrame.Rotate(const Angle: real; const AVector3d: TVector3d;
  const Axis: TAxis): TVector3d;
{ Pre: AVector3d <> nil & Angle is in radians
  Ret: A vector rotated around the local axis 'Axis' with the specified
  angle. }
var
  RotationMatrix: TGLMatrix;
  GlobalVector: TVector3d;
  RotatedVector: TVector3d;
begin
  RotationMatrix := TGLMatrix.Create;
  RotationMatrix.SetRotationMatrix(Angle, Axis);
  GlobalVector := Local2Canonical(AVector3d);
  RotatedVector := RotationMatrix.Multiply(AVector3d);
  Result := Canonical2Local(RotatedVector);
  RotationMatrix.Destroy;
  GlobalVector.Destroy;
  RotatedVector.Destroy;
end;

procedure TCoordinateFrame.Assign(AFrame: TCoordinateFrame);
begin
  FONB.Assign(AFrame.ONB);
  FOrigin.Assign(AFrame.Origin);
  FLCTransformationList.Destroy;
  FCLTransformationList.Destroy;
  SetTransformationLists;
end;

end.
